from django.shortcuts import render
from rest_framework.views import APIView
import pickle, base64
from rest_framework.response import Response
from rest_framework import status
from django_redis import get_redis_connection


from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerialzier, CartSelectedSerializer
from goods.models import SKU


# Create your views here.

class CartView(APIView):
    """购物车视图"""
    def perform_authentication(self, request):
        """延后认证, 因为购物车对所有人包含未登录用户开放"""
        pass


    def post(self, request):
        """添加购物车"""
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        # 创建响应对象
        response = Response(serializer.data, status=status.HTTP_201_CREATED)

        try:
            user = request.user  # 获取登录用户， 首次获取会做认证
            # 此处为登录用户 数据存储到redis
            """
            cart_user_id: {sku_id_16: 1}   hash

            hincrby(cart_1, sku_id_16, 2)  # 如果sku_id,已存在,直接会做增量计算

            selected_user_id :{sku_id}  set
            """
            # 创建redis连接对象
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # pl.hincrby('cart_%d' % user.id, sku_id, count)
            pl.hincrby('cart_%d' % user.id, sku_id, count)
            if selected:  # 判断当前商品是否勾选， 把勾选的商品的商品sku_id 添加到set集合中
                pl.sadd('selected_%d' % user.id, sku_id)
            pl.execute()
            # print('a')
        except:
            # 未登录存储到cookie

            """
                {
            sku_id: {
                "count": xxx,  // 数量
                "selected": True  // 是否勾选
            },
            sku_id: {
                "count": xxx,
                "selected": False
            },
            ...
            }
            """
            # 获取cookie的购物车数据
            cart_cookie = request.COOKIES.get('carts')

            # 判断是否有购物车数据
            if cart_cookie:
                # 把字符串转python中的字典
                # 把字符串转换成bytes类型字符串
                cart_cookie_bytes = cart_cookie.encode()
                # 把bytes类型字符串转换成bytes类型的ascii码
                cart_ascii_bytes = base64.b64decode(cart_cookie_bytes)
                # 把bytes类型的ascii码转换成python中的字幕
                cart_dict = pickle.loads(cart_ascii_bytes)
            else:   # 无购物车数据
                cart_dict = {}


            # 判断本次添加的商品是否在购物车中存在， 存在做增量计算
            if sku_id in cart_dict:
                origin_count = cart_dict[sku_id]['count']
                count += origin_count

            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 把python字典转换成字符串
            cart_ascii_bytes = pickle.dumps(cart_dict)
            cart_cookie_bytes = base64.b64encode(cart_ascii_bytes)
            cart_str = cart_cookie_bytes.decode()


            response.set_cookie('carts', cart_str)


        return response



    def get(self, request):
        """查询购物车"""
        try:
            user = request.user
            # 如果获取到user 说明为已登录用户

        except:
            # 否则为未登录用户  获取cookie
            user = None
        else:
            # 如果获取到user 需操作redis db
            # 创建数据库连接对象
            redis_conn = get_redis_connection('cart')
            # 获取hash数据 {sku_id: 1, sku_id2: 2}
            cart_redis_dict = redis_conn.hgetall('cart_%d' % user.id)
            # 获取set数据
            selected_ids = redis_conn.smembers('selected_%d' % user.id)
            # 把redis购物车数据转换成和cookie购物车数据格式一致

            # 定义一个用来转换数据格式的大字典
            cart_dict = {}
            for sku_id_bytes in cart_redis_dict:
                cart_dict[int(sku_id_bytes)] = {
                    'count': int(cart_redis_dict[sku_id_bytes]),
                    'selected': sku_id_bytes in selected_ids
                }

        if not user:
            # 如果没有获取到user说明当期是未登录用户操作cookie 获取购物车数据
            cart_str = request.COOKIES.get('carts')
            # 判断是否有cookie购物车数据
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 获取购物车中商品的sku模型
        skus = SKU.objects.filter(id__in=cart_dict.keys())

        # 遍历sku查询集， 给每个模型追加两个属性
        for sku in skus:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 创建序列化器进行序列化操作
        serializer = CartSKUSerializer(skus, many=True)
        return Response(serializer.data)






    def put(self, request):
        """修改购物车"""
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        response = Response(serializer.data)
        try:
            user = request.user
        except:
            user = None
        else:
            # 已登录操作
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 创建redis连接对象 hash字典
            # 勾选状态 set集合
            # 修改指定sku_id 的数据， 覆盖hash字典中的sku_id 的 value
            pl.hset('cart_%d' % user.id, sku_id, count)
            # 修改商品的勾选状态
            if selected:
                pl.sadd('selected_%d' % user.id, sku_id)
            else:
                pl.srem('selected_%d' % user.id, sku_id)
            pl.execute()

        if not user:
            # 未登录用户 使用cookie
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
                if sku_id in cart_dict:
                    # 覆盖数据和勾选状态
                    cart_dict[sku_id] = {
                        'count': count,
                        'selected': selected
                    }
                cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
                response.set_cookie('carts', cart_str)

        return response





    def delete(self, request):
        """删除购物车"""
        serializer = CartDeleteSerialzier(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get('sku_id')

        response = Response(status=status.HTTP_204_NO_CONTENT)

        try:
            user = request.user
        except:
            user = None
        else:
            # 已登录用户
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 把本次要删除的sku_id 从has 字典中删除
            pl.hdel('cart_%d' % user.id, sku_id)
            # 把本次要删除的sku_id从set集合删除
            pl.srem('selected_%d' % user.id, sku_id)
            pl.execute()

        if not user:
            # 未登录用户操作cookie 购物车数据
            # 获取cookie
            cart_str = request.COOKIES.get('carts')
            # 把 cart_str 转化 cart_dict
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))

                # 把要删除的ID 从字典中移除
                if sku_id in cart_dict:
                    del cart_dict[sku_id]
                if len(cart_dict.keys()):  # 若cookie中还包含商品
                    # 把cart_dict 转化成cart_str
                    cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
                    # 设置cookie
                    response.set_cookie('carts', cart_str)
                else:
                    response.delete_cookie('carts')

        return response



class CartSelectedView(APIView):
    """购物车全选"""
    def perform_authentication(self, request):
        """延后认证, 因为购物车对所有人包含未登录用户开放"""
        pass


    def put(self, request):
        """添加购物车"""
        serializer = CartSelectedSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data.get('selected')

        response = Response(serializer.data)

        try:
            user = request.user
        except:
            user = None
        else:
            # 已登录查询redis
            redis_conn = get_redis_connection('cart')
            # hash字典获取
            cart_redis_dict = redis_conn.hgetall('cart_%d' % user.id)
            # 判断是否全选或者取消全选
            if selected:
                # 如果是全选，则把所有sku_id添加到set集合中
                redis_conn.sadd('selected_%d' % user.id, *cart_redis_dict.keys())
            else:
                # 如果取消全选， 则把移除sku_id
                redis_conn.srem('selected_%d' % user.id, *cart_redis_dict.keys())

        if not user:
            # 未登录用户查询cookie
            cart_str = request.COOKIES.get('carts')
            # cart_str 转化 cart_dict
            if cart_str:   # 如果cookie存在
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
                # 遍历cookie 字典
                for sku_id in cart_dict:
                    sku_id_dict = cart_dict[sku_id]
                    # 是全选把selected全部改为true 否则 false
                    sku_id_dict['selected'] = selected

                # 把cart_dict转化成cart_str
                cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
                # 设置cookie
                response.set_cookie('carts', cart_str)

        return response